#include "DynamicQObject.h"
#import <objc/Object.h>
#import "../lmmi/Object+RefCount.h"
#import "../lmmi/Object+Loggin.h"

VirtualSlot::VirtualSlot(SEL selector) : sel(selector)
{
    this->target = nil;
}

VirtualSlot::~VirtualSlot()
{
    [this->target release];
}

const char *VirtualSlot::slotRepresentation()
{
    return sel_get_name(this->sel);
}

void VirtualSlot::setTarget(id target)
{
    this->target = [target retain];
    this->imp = get_imp([this->target class], this->sel);
    if(this->imp == NULL){
        fprintf(stderr, "no existe implementacion para %s\n", sel_get_name(sel));
    }
}


bool DynamicQObject::connect(QObject *obj, const char *signal, id objcObj, VirtualSlot *slot)
{
    QByteArray theSignal = QMetaObject::normalizedSignature(signal);
    QByteArray theSlot = QMetaObject::normalizedSignature(slot->slotRepresentation());

/*
    No necesitamos comprobar, por ahora, el tipo de argumentos, luego veremos
    if(!QMetaObject::checkConnectArgs(theSignal, theSlot)){
        return false;
    }
*/

    int signalId = obj->metaObject()->indexOfSignal(theSignal);
    if(signalId < 0){
        qWarning("Signal %s inválida, borrando slot: %s\n", signal, slot->slotRepresentation());
        delete(slot);
        return false;
    }

    int slotId = slotIndices.value(theSlot, -1);
    if(slotId < 0){
        slotId = slotList.size();
        slotIndices[theSlot] = slotId;
        slot->setTarget(objcObj);
        slotList.append(slot);
    }else{
        qWarning("Selector: 0x%x %s repetido\n", slot, slot->slotRepresentation());
        // El slot ya fue insertado en la lista, entonces no es necesario guardarlo mas
        delete slot;
    }

    return QMetaObject::connect(obj, signalId, this, slotId + metaObject()->methodCount());
}

int DynamicQObject::qt_metacall(QMetaObject::Call c, int _id, void **arguments)
{
    _id = QObject::qt_metacall(c, _id, arguments);
    if (_id < 0 || c != QMetaObject::InvokeMetaMethod) 
        return _id;
    Q_ASSERT(_id < slotList.size());
    
    slotList[_id]->call(sender(), arguments);
    return -1;
}

